#ifndef CSUGL_TEXTURE_H
#define CSUGL_TEXTURE_H

#include "../core/core.h"

#include "../vendor/glm/glm/glm.hpp"
namespace csugl {

    enum TextureWrapType
    {
        REPEAT =            0x01,
        MIRRORED_REPEAT =   0x02,
        CLAMP_TO_EDGE =     0x03,
        CLAMP_TO_BORDER =   0x04
    };
    struct TextureWrap
    {
        TextureWrap(TextureWrapType s_type = REPEAT,
                    TextureWrapType t_type = REPEAT);
        uint32_t _s_type, _t_type;
    };

    enum TextureFilterType
    {
        NEAREST =   1 << 0,
        LINEAR =    1 << 1,

        N_SAMPLE =  1 << 2,
        L_SAMPLE =  1 << 3,

        N_INTER =   1 << 4,
        L_INTER =   1 << 5,
    };
    struct TextureFilter
    {
        TextureFilter(TextureFilterType min_type = LINEAR,
                      TextureFilterType mag_type = LINEAR);
        uint32_t _min_type, _mag_type;
    };

    struct TextureParameter
    {
        TextureParameter(TextureWrap    tex_wrap = {},
                         TextureFilter  tex_filter = {},
                        bool            gen_mipmap = true)
            : wrap(tex_wrap), filter(tex_filter)
        {
        }
        TextureWrap wrap;
        TextureFilter filter;
        bool gen_mipmap;
    };

    struct Texture2DProp
    {
        Texture2DProp(int               width,
                      int               height,
                      int               channel = 3,
                      TextureParameter  param = {})
            : width(width), height(height), channel(channel), 
              param(param)
        {
        }
        int width, height, channel;
        TextureParameter param;
    };

    template <typename T>
    struct Texture {
        int width, height, channel;
        uint32_t tex_ID;
        Texture(int width, int height, int channel) : width(width), height(height), channel(channel) {}
        virtual void bind() const = 0;
    };

    namespace il { struct MImage; }

    struct Texture2D : public Texture<uint8_t> {
        // Texture2D(int width, int height, int channel = 3, const uint8_t* data = nullptr);
        Texture2D(Texture2DProp prop, const uint8_t* data = nullptr);

        void bind() const override;

        void update_data(const glm::ivec2 &offset, const glm::ivec2 &size, const uint8_t* data);

        // static Ref<Texture2D> Create(Ref<il::MImage> meta_image);
        // static Ref<Texture2D> Create(int width, int height, int channel, const uint8_t *data = nullptr);

        static Ref<Texture2D> Create(TextureParameter param, Ref<il::MImage> meta_image);
        static Ref<Texture2D> Create(Texture2DProp prop, const uint8_t *data = nullptr);
    };

    struct TextureUnit {
        void active(uint32_t index);
        const static uint32_t max_unit_num;
    };

}

#endif // !CSUGL_TEXTURE_H